package com.gitee.wsl.common.chart.sample.line

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import com.gitee.wsl.android.ext.math.percent
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.listener.click.PointPosition
import com.gitee.wsl.common.chart.render.background.axis.line.CategoryLineAxis
import com.gitee.wsl.common.chart.render.background.axis.line.DataLineAxis
import com.gitee.wsl.common.chart.render.foreground.PlotCustomLine
import com.gitee.wsl.common.chart.render.foreground.info.Anchor
import com.gitee.wsl.common.chart.render.foreground.info.PlotLegendItem
import com.gitee.wsl.common.chart.sample.AbstractAxesChart
import com.gitee.wsl.common.chart.sample.line.model.BaseLineData
import com.gitee.wsl.android.ui.ext.type.LineExt
import com.gitee.wsl.ext.math.Dimensions
import timber.log.Timber

/**
 * @ClassName XChart
 * @Description 所有线类，如折线，曲线等图表类的基类,在此主要用于Key及坐标系的绘制。
 *
 * @author XiongChuanLiang<br/>
 *         (xcl_168@aliyun.com)
 *
 */

abstract class AbstractLineChart( touchCheckAble: com.gitee.wsl.common.ui.api.TouchCheckAble? = null) :AbstractAxesChart(touchCheckAble){

     var bezierControls:Pair<PointF,PointF> = PointF(0f,0f) to PointF(0f,0f)

    // 批注
     var anchorSet: List<Anchor> = mutableListOf ()

    // 用于绘制定制线(分界线)
     var customLine: PlotCustomLine? = null

    //标签和对象依哪种风格居中显示
    var barCenterStyle = ChartEnum.BarCenterStyle.TICKMARKS

    //图例
     val lstKey= mutableListOf<BaseLineData>()


     override fun getAxisYPos(location: ChartEnum.AxisLocation): Float {
        return if (dataAxis.isAxisStdStatus && categoryAxis.isAxisStdStatus) {
            getVPDataAxisStdY(dataAxis)
        } else {
            super.getAxisYPos(location)
        }
    }

    /**
     * 绘制底部标签轴
     */
    override fun drawClipDataAxisGridlines(canvas: Canvas,
                                           dataAxis:DataLineAxis,
                                           pos: ChartEnum.AxisLocation
    ) {
        // 数据轴数据刻度总个数
        val tickCount: Int = dataAxis.axisTickCount
        var labelTickCount = tickCount
        if (0 == tickCount) {
            Timber.d( "数据源个数为0!")
            return
        } else if (1 == tickCount) // label仅一个时右移
            labelTickCount = 0

        // 与柱形图不同，无须多弄一个
        var XSteps = 0.0f
        var YSteps = 0.0f

        // 标签轴(X 轴)
        var axisX = 0.0f
        var axisY = 0.0f

        when (pos) {
            ChartEnum.AxisLocation.LEFT, ChartEnum.AxisLocation.RIGHT, ChartEnum.AxisLocation.VERTICAL_CENTER -> {
                YSteps = getVerticalYSteps(labelTickCount)
                axisX = getAxisXPos(pos)
                axisY = bodyViewport.bottom
            }
            ChartEnum.AxisLocation.TOP, ChartEnum.AxisLocation.BOTTOM, ChartEnum.AxisLocation.HORIZONTAL_CENTER -> {
                XSteps = getVerticalXSteps(labelTickCount)
                axisY = getAxisYPos(pos)
                axisX = bodyViewport.left
            }
            //else -> Log.e(LnChart.TAG, "未知的枚举类型 .")
        }

        plotGrid.drawClipDataAxisGridlines(canvas, dataAxis, bodyViewport, XSteps, YSteps, axisX, axisY, tickCount+1, pos,true)

    }

    /**
     * 绘制底部标签轴
     */
    override  fun drawClipCategoryAxisGridlines(canvas: Canvas,
                                        categoryAxis:CategoryLineAxis,
                                        pos: ChartEnum.AxisLocation
    ) {
        // 得到标签轴数据集
        val dataSet: List<String> = categoryAxis.dataSet

        var j = 0
        val tickCount = dataSet.size
        if (0 == tickCount) {
            Timber.d( "分类轴数据源为0!")
            return
        } else if (1 == tickCount) // label仅一个时右移
        {
            j = 1
        }
        val labeltickCount = getCategoryAxisLabelTickCount(categoryAxis)

        // 与柱形图不同，无须多弄一个
        var XSteps = 0.0f
        var YSteps = 0.0f

        // 标签轴(X 轴)
        var axisX = 0.0f
        var axisY = 0.0f

        if (ChartEnum.AxisLocation.LEFT == pos || ChartEnum.AxisLocation.RIGHT == pos || ChartEnum.AxisLocation.VERTICAL_CENTER == pos) {
            YSteps = getVerticalYSteps(labeltickCount)
            axisX = getAxisXPos(pos)
            axisY = bodyViewport.bottom
        } else { // TOP BOTTOM
            XSteps = getVerticalXSteps(labeltickCount)
            axisY = getAxisYPos(pos)
            axisX = bodyViewport.left
        }

        plotGrid.drawClipCategoryAxisGridlines(canvas, categoryAxis, bodyViewport, xCoordFirstTickmarksBegin, barCenterStyle,j,XSteps, YSteps, axisX, axisY, tickCount, pos)

    }

    /*open fun isPlotClickArea(x: Float, y: Float): Boolean {
        if (selectHelper!=null && !selectHelper!!.getListenItemClickStatus()) return false
        if (x.compareTo(left) == -1) return false
        if (x.compareTo(right) == 1) return false
        if (y.compareTo(bodyViewport.top) == -1) return false
        return y.compareTo(bodyViewport.bottom) != 1
    }*/

    /**
     * 返回当前点击点的信息
     *
     * @param x
     * 点击点X坐标
     * @param y
     * 点击点Y坐标
     * @return 返回对应的位置记录
     */
    open fun getPositionRecord(x: Float, y: Float): PointPosition? {
        return selectHelper.getPointRecord(x, y)
    }

    // 遍历曲线
    protected  fun drawBezierCurveLine(
        canvas: Canvas, paint: Paint,
        bezierPath: Path, lstPoints: List<PointF>
    ) {
        paint.style = Paint.Style.STROKE
        val count = lstPoints.size
        if (count <= 2) return  // 没有或仅一个点就不需要了
        if (count == 3) {
            bezierPath.moveTo(lstPoints[0].x, lstPoints[0].y)
            val ctl3 = Dimensions.percent(
                lstPoints[1], 0.5f,
                lstPoints[2], 0.8f
            )
            bezierPath.quadTo(
                ctl3.x, ctl3.y, lstPoints[2].x,
                lstPoints[2].y
            )
            canvas.drawPath(bezierPath, paint)
            bezierPath.reset()
            return
        }
        val axisMinValue: Float = bodyViewport.bottom
        for (i in 0 until count) {
            if (i < 3) continue

            // 连续两个值都为0,控制点有可能会显示在轴以下，则此种情况下，将其处理为直线
            if (lstPoints[i - 1].y >= axisMinValue
                && lstPoints[i].y >= axisMinValue
            ) {
                bezierPath.reset()
                bezierPath.moveTo(
                    lstPoints[i - 2].x,
                    lstPoints[i - 2].y
                )

                // change by chenqiang
                if (lstPoints[i - 2].y >= axisMinValue) { //连续3个点为0
                    bezierPath.lineTo(
                        lstPoints[i - 1].x,
                        lstPoints[i - 1].y
                    )
                } else {
                    bezierControls=LineExt.curve3(
                        lstPoints[i - 2], lstPoints[i - 1],
                        lstPoints[i - 3], lstPoints[i],
                    )
                    bezierPath.quadTo(
                        bezierControls.first.x, bezierControls.first.y,
                        lstPoints[i - 1].x, lstPoints[i - 1].y
                    )

                    // i-2与i-1之间的曲线
                    canvas.drawPath(bezierPath, paint)
                    bezierPath.reset()
                }

                // i-1与i之间的直线
                canvas.drawLine(
                    lstPoints[i - 1].x, lstPoints[i - 1].y,
                    lstPoints[i].x, lstPoints[i].y, paint
                )
                continue
            }
            bezierControls=LineExt.curve3(
                lstPoints[i - 2], lstPoints[i - 1],
                lstPoints[i - 3], lstPoints[i]
            )

            // change by chenqiang
            drawBezierCurvePath(
                canvas, paint, bezierPath,
                lstPoints[i - 2], lstPoints[i - 1], bezierControls
            )
        }
        if (count > 3) {
            val stop = lstPoints[count - 1]
            // PointF start = lstPoints.get(lstPoints.size()-2);
            bezierControls=LineExt.curve3(
                lstPoints[count - 2], stop,
                lstPoints[count - 3], stop
            )
            drawBezierCurvePath(
                canvas, paint, bezierPath,
                lstPoints[count - 2], lstPoints[count - 1],
                bezierControls
            )
        }
    }

    // 绘制曲线
   protected fun drawBezierCurvePath(
        canvas: Canvas, paint: Paint,
        bezierPath: Path, start: PointF, stop: PointF, bezierControls: Pair<PointF,PointF>
    ) {
        bezierPath.reset()
        bezierPath.moveTo(start.x, start.y)

//		Log.v(TAG, "start.y = " + start.y + " stop.y = " + stop.y);
//		Log.v(TAG, "bezierControls.first.y = " + bezierControls.first.y
//				+ " bezierControls.second.y = " + bezierControls.second.y);

        // change by chenqiang
        calcBezierCurvePathAxisMinValue(bezierPath, start, stop, bezierControls)
        canvas.drawPath(bezierPath, paint)
        bezierPath.reset()
    }


    // add by chenqiang
    protected  fun calcBezierCurvePathAxisMinValue(
        bezierPath: Path, start: PointF,
        stop: PointF, bezierControls: Pair<PointF,PointF>
    ) {
        // Log.v(TAG, "start.y = " + start.y + " stop.y = " + stop.y);
        // Log.v(TAG, "bezierControls.first.y = " + bezierControls.first.y
        // + " bezierControls.second.y = " + bezierControls.second.y);
        val axisMinValue: Float = bodyViewport.bottom
        if (start.y >= axisMinValue && stop.y >= axisMinValue) {
            bezierPath.lineTo(stop.x, stop.y)
        } else {
            if (bezierControls.first.y >= axisMinValue
                && bezierControls.second.y >= axisMinValue
            ) {
                bezierPath.lineTo(stop.x, stop.y)
            } else if (bezierControls.first.y >= axisMinValue
                && bezierControls.second.y < axisMinValue
            ) {
                bezierPath.cubicTo(
                    bezierControls.first.x, axisMinValue,
                    bezierControls.second.x, bezierControls.second.y, stop.x,
                    stop.y
                )
            } else if (bezierControls.first.y < axisMinValue
                && bezierControls.second.y >= axisMinValue
            ) {
                bezierPath.cubicTo(
                    bezierControls.first.x, bezierControls.first.y,
                    bezierControls.second.x, axisMinValue, stop.x, stop.y
                )
            } else {
                bezierPath.cubicTo(
                    bezierControls.first.x, bezierControls.first.y,
                    bezierControls.second.x, bezierControls.second.y, stop.x,
                    stop.y
                )
            }
        }
    }

    override fun createLegendData(): List<PlotLegendItem> {
        var key = ""
        val legendList= mutableListOf<PlotLegendItem>()
        for (cData in lstKey) {
            key = cData.label
            if (key.isEmpty()) continue
            legendList.add(PlotLegendItem(key,cData.lineColor,cData.plotLine.plotDot))
        }
        return legendList
    }
}